﻿using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;
using Volo.Abp.Uow;
using YAKEJI.Abp.Domain.Repositories;
using YAPACS.BusinessObjects.Exams;
using YAPACS.BusinessObjects.Managements.ExpertGroups;
using YAPACS.Organizations;
using YAPACS.RisServer.Abstractions;
using YAPACS.RisServer.Services.Dtos;
using YAPACS.RisServer.Workflows.Study;
using YAPACS.Workflows;

namespace YAPACS.RisServer.Services;

public class StudyService(IRepository<Study, Guid> studyRepository, ICurrentUserOrganization currentUserOrganization,
    IRepository<Department, Guid> departmentRepository, IUnitOfWorkManager unitOfWorkManager,
    IRepository<Exam, Guid> examRepository, IRepository<Patient, Guid> patientRepository, IExamNumberService examNumberService, 
    IApplyConsultation applyConsultation)
    : DomainService, IStudyService, ITransientDependency
{
    private readonly IUnitOfWorkManager _unitOfWorkManager = unitOfWorkManager;
    private readonly IRepository<Study, Guid> _studyRepository = studyRepository;
    private readonly IRepository<Department, Guid> _departmentRepository = departmentRepository;
    private readonly ICurrentUserOrganization _currentUserOrganization = currentUserOrganization;
    private readonly IRepository<Exam, Guid> _examRepository = examRepository;
    private readonly IRepository<Patient, Guid> _patientRepository = patientRepository;
    private readonly IExamNumberService _examNumberService = examNumberService;
    private readonly IApplyConsultation _applyConsultation = applyConsultation;

    public async Task<WorkflowOutput> GetStudiesAsync(DataGridRequest request)
    {
        try
        {
            var workflowOutput = new WorkflowOutput { Success = true };
            //查询数据
            var query = await _studyRepository.GetQueryableAsync();
            var department = await _departmentRepository.GetAsync(_currentUserOrganization.DepartmentId.Value);
            if (request.UserData != null && request.UserData.Count > 0)
            {
                string number = request.UserData.GetValueOrDefault("number") as string;
                query = query.Where(e => string.IsNullOrWhiteSpace(number) || e.AccessionNumber == number || e.PatientId == number || e.StudyId == number);
                string dateType = request.UserData.GetValueOrDefault("date") as string;
                var today = DateTime.Today;
                var dateRange = dateType switch
                {
                    "today" => [today, today.AddDays(1)],
                    "yesterday" => [today.AddDays(-1), today],
                    "lastThreeDays" => [today.AddDays(-3), today.AddDays(1)],
                    _ => Array.Empty<DateTime>()
                };
                if (dateRange.Length > 0)
                {
                    query = query.Where(e => (e.StudyDateTime >= dateRange[0] && e.StudyDateTime < dateRange[1]) || (e.CreationTime >= dateRange[0] && e.CreationTime < dateRange[1]));
                }
            }
            //else
            //{
            //    query = query.Where(e => e.Exams.Count == 0 );
            //}
            query = query.Where(e => e.Device.Station.Room.Department == department);
            if (request.Sort == null)
            {
                query = query.OrderByDescending(e => e.StudyDateTime);
            }
            else
            {
                var sort = request.Sort[0];
                query = sort.Selector switch
                {
                    "accessionNumber" => sort.Desc ? query.OrderByDescending(e => e.AccessionNumber) : query.OrderBy(e => e.AccessionNumber),
                    "patientName" => sort.Desc ? query.OrderByDescending(e => e.PatientName) : query.OrderBy(e => e.PatientName),
                    "patientSex" => sort.Desc ? query.OrderByDescending(e => e.PatientSex) : query.OrderBy(e => e.PatientSex),
                    "patientAge" => sort.Desc ? query.OrderByDescending(e => e.PatientAge) : query.OrderBy(e => e.PatientAge),
                    "studyId" => sort.Desc ? query.OrderByDescending(e => e.StudyId) : query.OrderBy(e => e.StudyId),
                    "patientId" => sort.Desc ? query.OrderByDescending(e => e.PatientId) : query.OrderBy(e => e.PatientId),
                    "deviceName" => sort.Desc ? query.OrderByDescending(e => e.Device.Name) : query.OrderBy(e => e.Device.Name),
                    "studyDateTime" => sort.Desc ? query.OrderByDescending(e => e.StudyDateTime) : query.OrderBy(e => e.StudyDateTime),
                    "manufacturer" => sort.Desc ? query.OrderByDescending(e => e.Manufacturer) : query.OrderBy(e => e.Manufacturer),
                    "manufacturerModelName" => sort.Desc ? query.OrderByDescending(e => e.ManufacturerModelName) : query.OrderBy(e => e.ManufacturerModelName),
                    _ => query.OrderByDescending(e => e.StudyDateTime)
                };
            }
            var data = await AsyncExecuter.ToListAsync(
                query
                .Skip(request.Skip)
                .Take(request.Take)
                .Select(e => new
                {
                    e.Oid,
                    e.StudyKey,
                    e.PatientId,
                    e.PatientName,
                    e.PatientSex,
                    e.StudyId,
                    DeviceName = e.Device != null ? e.Device.Name : null,
                    e.AccessionNumber,
                    e.StudyDateTime,
                    e.Manufacturer,
                    e.ManufacturerModelName,
                    e.PatientAge,
                    Apply = e.Exams.Count > 0
                }));
            var totalCount = data.Count;
            workflowOutput.Data = new DataGridDto() { Rows = data, TotalCount = totalCount };
            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public async Task<WorkflowOutput> CreateStudyExamAsync(IList<Guid> studyIds)
    {
        try
        {
            if (studyIds.Count == 0) throw new Exception("未选择任何检查");
            var studyId = studyIds[0];
            var study = await _studyRepository.GetAsync(studyId);
            if (study.Exams.Count >= 1)
            {
                foreach (var exam in study.Exams)
                {
                    exam.IsConsultation = true;
                    exam.ExpertGroup = exam.Department.GetExpertGroup();
                }
                return new WorkflowOutput { Success = true, Data = study.Exams[0].Oid };
            }
            else
            {
                var exam = await _examRepository.NewEntityAsync();

                //患者
                var patient = await _patientRepository.NewEntityAsync();
                patient.PatientId = study.PatientId;
                patient.Name = study.PatientName;
                patient.BirthDate = study.PatientBirthDate;
                patient.Sex = study.PatientSex switch
                {
                    "M" => PatientSex.Male,
                    "F" => PatientSex.Female,
                    "O" => PatientSex.Other,
                    _ => null
                };

                exam.Patient = patient;

                if (!string.IsNullOrWhiteSpace(study.PatientAge))
                {
                    var age = study.PatientAge.Trim().ToUpper();
                    var ageUnit = AgeUnit.Year;
                    ageUnit = age[^1] switch
                    {
                        'Y' => AgeUnit.Year,
                        'M' => AgeUnit.Month,
                        'D' => AgeUnit.Day,
                        'H' => AgeUnit.Hour,
                        _ => AgeUnit.Year
                    };

                    var ageValue = 0;

                    if (age[^1] >= 'A' && age[^1] <= 'Z')
                    {
                        _ = int.TryParse(age[..^1], out ageValue);
                    }
                    else
                    {
                        _ = int.TryParse(age, out ageValue);
                    }

                    exam.AgeValue = ageValue;
                    exam.AgeUnit = ageUnit;
                }

                exam.AccessionNumber = study.AccessionNumber;
                //科室
                exam.Department = study.Device.Station.Room.Department;
                //设备
                exam.ExamDevice = study.Device;
                exam.DeviceType = study.Device.DeviceType;
                exam.StoreService = study.StoreService;
                exam.IsConsultation = true;
                exam.ExpertGroup = exam.Department.GetExpertGroup();
                var studies = await _studyRepository.GetListAsync(e => studyIds.Contains(e.Oid));
                exam.Studies.AddRange(studies);
                await _examNumberService.SetNumberAsync(exam);
                return new WorkflowOutput { Success = true, Data = exam.Oid };
            }
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public async Task<WorkflowOutput> ApplyConsultationAsync(IList<Guid> examIds)
    {
        try
        {
            var exams = await _examRepository.GetListAsync(e => examIds.Contains(e.Oid));
            var department = await _departmentRepository.GetAsync(_currentUserOrganization.DepartmentId.Value);
            var groupList=(from a in exams
                   group a by a.Department into aGroup
                   select aGroup.Key).ToList();
            if (groupList.Count > 1)
            {
                throw new Exception("所选数据不在同一个科室");
            }
            List<string> errorMessages = [];

            foreach (var exam in exams)
            {
                if (exam.Department != department)
                {
                    errorMessages.Add($"当前检查【{exam.Patient.Name}({exam.AccessionNumber})】不属于本科室");
                }
            }
            if (errorMessages.Count > 0)
            {
                throw new Exception(string.Join("<br>", errorMessages));
            }
            var workflowOutput = await _applyConsultation.InvokeAsync(new WorkflowInput { { "Exams", exams } });
            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }
}
